//
//  TTPopoverViewController.swift
//  TTCOM-macOS
//
//  Created by Toj on 4/28/21.
//

import Cocoa

@objc public protocol TTPopoverViewControllerDelegate: NSObjectProtocol {
    @objc optional func popover(viewController: TTPopoverViewController, didTapRowAt item: TTPopoverViewController.TTItem)
}

open class TTPopoverViewController: NSViewController {
    
    public var items: [TTItem]? {
        didSet { setupMakeAddSubviews() }
    }
    
    public lazy var appearance: TTAppearance = TTAppearance()
    
    public var backgroundColor: NSColor = .white {
        didSet {
            view.layer?.backgroundColor = backgroundColor.cgColor
        }
    }
    
    public var bottomInset: CGFloat = 0
    public var itemLineSpacing: CGFloat = 0
    public var contentSize: CGSize = .zero
    
    public weak var delegate: TTPopoverViewControllerDelegate?
    
    private var aPopover: NSPopover?
    private var popover: NSPopover? {
        set { aPopover = nil }
        
        get {
            if aPopover != nil { return aPopover }
            
            let view = NSPopover()
            view.appearance = NSAppearance(named: NSAppearance.Name.aqua)
            view.behavior = .transient
            view.contentViewController = self
            view.delegate = self
            aPopover = view
            return aPopover
        }
    }
    
    private var buttons: [TTButton]?
    
    deinit {
        print(#function + className)
    }
}

public extension TTPopoverViewController {
    
    override func loadView() {
        view = TTPopoverView()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.wantsLayer = true
    }
    
    override func viewWillLayout() {
        super.viewWillLayout()
        
        setupMakeLayoutSubviews()
    }
}

public extension TTPopoverViewController {
    
    func showRelative(of positioningView: NSView, preferredEdge: NSRectEdge) {
        let itemCount = CGFloat(buttons?.count ?? 0)
        let height = (appearance.itemHeight + itemLineSpacing) * itemCount + bottomInset
        contentSize.height = height
        popover?.contentSize = contentSize
        popover?.show(relativeTo: positioningView.bounds, of: positioningView, preferredEdge: preferredEdge)
    }
}

extension TTPopoverViewController: NSPopoverDelegate {
    public func popoverWillClose(_ notification: Notification) {
        popover = nil
    }
}

private extension TTPopoverViewController {
    @objc func didTapItem(sender: NSButton) {
        let index = sender.tag
        guard let item = items?[index] else { return }
        
        delegate?.popover?(viewController: self, didTapRowAt: item)
        popover?.close()
    }
}

private extension TTPopoverViewController {
    
    func setupMakeAddSubviews() {
        guard let items = items else { return }
        buttons?.forEach({ view in
            view.removeFromSuperview()
        })
        
        buttons = []
        var index = 0
        items.forEach({ item in
            item.index = index
            let button = setupMakeViews(item)
            button.tag = index
            
            buttons?.append(button)
            view.addSubview(button)
            index += 1
        })
    }
    
    func setupMakeViews(_ item: TTItem) -> TTButton {
        let view = TTButton()
        view.tt_addTarget(self, action: #selector(didTapItem(sender:)), for: .leftMouseUp)
        
        view.layer?.cornerRadius = appearance.cornerRadius
        view.tt_spacing = appearance.spacing
        view.tt_titleFont = appearance.titleFont
        view.tt_titleAlignment = appearance.titleAlignment
        view.tt_backgroundColor = appearance.backgroundColor
        
        setupTitles(item, view: view)
        setTitleColors(item, view: view)
        setImages(item, view: view)
        setBackgroundImages(item, view: view)
        
        return view
    }
    
    func setupMakeLayoutSubviews() {
        
        let selfWidth = view.frame.size.width
        let selfHeight = view.frame.size.height
        let height = appearance.itemHeight
        let totalHeight = height * CGFloat(buttons?.count ?? 0)
        let condition = totalHeight < selfHeight
        
        assert(condition, "Too high: totalHeight > selfHeight")
        
        var width = appearance.itemWidth
        if  width == 0 { width = selfWidth }
        let x = (selfWidth - width) * 0.5
        var y: CGFloat = bottomInset
        
        buttons?.forEach({ view in
            view.frame = CGRect(x: x, y: y, width: width, height: height)
            y += height + itemLineSpacing
        })
    }
}

private extension TTPopoverViewController {
    
    func setupTitles(_ item: TTItem, view: TTButton) {
        view.tt_setTitle(item.title, for: .normal)
        if let style = item.titleStyle {
            view.tt_setTitle(style.hover, for: .normal)
            view.tt_setTitle(style.hover, for: .hover)
            view.tt_setTitle(style.press, for: .press)
            view.tt_setTitle(style.disabled, for: .disabled)
            view.tt_setTitle(style.selected, for: .selected)
        }
    }
    
    func setTitleColors(_ item: TTItem, view: TTButton) {
        var normal = appearance.titleColor
        if item.titleColorStyle?.normal != nil
        { normal = item.titleColorStyle?.normal }
        else if item.titleColor != nil
        { normal = item.titleColor }
        else if appearance.titleColorStyle?.normal != nil
        { normal = appearance.titleColorStyle?.normal }
        
        var hover = appearance.titleColorStyle?.hover
        if item.titleColorStyle?.hover != nil
        { hover = item.titleColorStyle?.hover }
        
        var press =  appearance.titleColorStyle?.press
        if item.titleColorStyle?.press != nil
        { press = item.titleColorStyle?.press }
        
        var disabled =  appearance.titleColorStyle?.disabled
        if item.titleColorStyle?.disabled != nil
        { disabled = item.titleColorStyle?.disabled }
        
        var selected =  appearance.titleColorStyle?.selected
        if item.titleColorStyle?.selected != nil
        { selected = item.titleColorStyle?.selected }
        
        view.tt_setTitleColor(normal, for: .normal)
        view.tt_setTitleColor(hover, for: .hover)
        view.tt_setTitleColor(press, for: .press)
        view.tt_setTitleColor(disabled, for: .disabled)
        view.tt_setTitleColor(selected, for: .selected)
    }
    
    func setImages(_ item: TTItem, view: TTButton) {
        view.tt_setImage(item.image, for: .normal)
        if let style = item.imageStyle {
            view.tt_setImage(style.hover, for: .normal)
            view.tt_setImage(style.hover, for: .hover)
            view.tt_setImage(style.press, for: .press)
            view.tt_setImage(style.disabled, for: .disabled)
            view.tt_setImage(style.selected, for: .selected)
        }
    }
    
    func setBackgroundImages(_ item: TTItem, view: TTButton) {
        var normal = appearance.backgroundImage
        if item.backgroundImageStyle?.normal != nil
        { normal = item.backgroundImageStyle?.normal }
        else if item.backgroundImage != nil
        { normal = item.backgroundImage }
        else if appearance.backgroundImageStyle?.normal != nil
        { normal = appearance.backgroundImageStyle?.normal }
        
        var hover = appearance.backgroundImageStyle?.hover
        if item.backgroundImageStyle?.hover != nil
        { hover = item.backgroundImageStyle?.hover }
        
        var press =  appearance.backgroundImageStyle?.press
        if item.backgroundImageStyle?.press != nil
        { press = item.backgroundImageStyle?.press }
        
        var disabled =  appearance.backgroundImageStyle?.disabled
        if item.backgroundImageStyle?.disabled != nil
        { disabled = item.backgroundImageStyle?.disabled }
        
        var selected =  appearance.backgroundImageStyle?.selected
        if item.backgroundImageStyle?.selected != nil
        { selected = item.backgroundImageStyle?.selected }
        
        view.tt_setBackgroundImage(normal, for: .normal)
        view.tt_setBackgroundImage(hover, for: .hover)
        view.tt_setBackgroundImage(press, for: .press)
        view.tt_setBackgroundImage(disabled, for: .disabled)
        view.tt_setBackgroundImage(selected, for: .selected)
    }
}

// 优先:
// TTItem > TTAppearance
// Style > 通用设置
public extension TTPopoverViewController {
    class TTItem: NSObject {
        // 通用设置
        public var title: String?
        public var titleColor: NSColor?
        public var image: NSImage?
        public var backgroundImage: NSImage?
        
        // 分别设置
        public var titleStyle: TTTitleStyle?
        public var titleColorStyle: TTColorStyle?
        public var imageStyle: TTImageStyle?
        public var backgroundImageStyle: TTImageStyle?
        
        public var index: Int = 0
    }
    
    class TTAppearance: NSObject {
        public var cornerRadius: CGFloat = 4
        public var spacing: CGFloat = 6
        public var titleFont: NSFont = NSFont.systemFont(ofSize: 14)
        public var titleAlignment: TTTitleAlignment = .right
        public var backgroundColor: NSColor = .white
        public var itemWidth: CGFloat = 0
        public var itemHeight: CGFloat = 0
        
        
        // 统一设置
        public var titleColor: NSColor?
        public var titleColorStyle: TTColorStyle?
        
        public var backgroundImage: NSImage?
        public var backgroundImageStyle: TTImageStyle?
    }
}
